
#include "Config.h"

CpuParams* Config::cpus;
map<int,int>* Config::consumerToChip;
map<int,int>* Config::consumerToCore;
map<int,int>* Config::producerToChip;
map<int,int>* Config::producerToCore;
int* Config::consumerIds;
int* Config::producerIds;
int Config::peakLength;
int Config::timeBetweenPeaks;
unsigned long Config::timeToRun;
string Config::containerType;
int Config::perChipContainersNum;
string Config::perChipContainerType;
/***** fields currently not in use ***************/
/*
bool Config::contentionStatistics;
bool Config::exitsStatistics;
string Config::consType;
string Config::prodType;
int Config::shortTaskLength;
int Config::longTaskRange;
int Config::consFailuresThreshold;
string Config::quasiType;
int Config::quasiFactor;
int Config::qRandomTries;
*/
/************************************************/

string* Config::stringSplit(const string str, const char seperator, int& arrLen)
{
	arrLen = 0;
	int strLen = (int)str.length();
	if(strLen == 0){return NULL;}
	for(int i = 0; i < strLen; i++)
	{
		if(str[i] == seperator){arrLen++;}
	}
	arrLen++;
	string* res = new string[arrLen];  
	int pos = 0;
	int i = 0;
	bool finished = false;
	while(!finished)
	{
		int new_pos = str.find(seperator,pos);
		if(new_pos == (int)string::npos)
		{
			new_pos = strLen;
			finished = true;
		}
		res[i] = str.substr(pos,new_pos-pos);
		pos = new_pos+1;
		i++;
	}
	return res;
}


int* Config::parseThreadCores(string coresString, int& coreNum)
{
	int arrLen = 0;
	string* strCores = stringSplit(coresString, ' ', arrLen);
	int* cores = new int[arrLen];  
	for(int i = 0; i < arrLen; i++)
	{
		cores[i] = atoi(strCores[i].c_str());
	}
	coreNum = arrLen;
	delete[] strCores;
	return cores;
}


int** Config::parseChipCores(string chips, int& chipNum, int& coresPerChip)
{
	string* chipsArr = stringSplit(chips,':',chipNum);
	int** chipCores = new int*[chipNum];  
	for(int i = 0; i < chipNum; i++)
	{
		string* procs = stringSplit(chipsArr[i],' ',coresPerChip);
		chipCores[i] = new int[coresPerChip];  
		for(int j = 0; j < coresPerChip; j++)
		{
			chipCores[i][j] = atoi(procs[j].c_str());
		}
		delete[] procs;
	}
	delete[] chipsArr;
	return chipCores;
}


int Config::getChipByCoreId(int coreId)
{
	for(int i = 0; i < cpus->chipNum; i++)
	{
		for(int j = 0; j < cpus->coresPerChip; j++)
		{
			if(cpus->chips[i][j] == coreId){return i;}
		}
	}
	return -1;
}


void Config::initThreadsToChipMap()   
{
	producerToChip = new map<int,int>();
	producerToCore = new map<int,int>();
	consumerToChip = new map<int,int>();
	consumerToCore = new map<int,int>();
	for(int i = 0; i < cpus->consThreadsNum; i++)
	{
		int index = i % cpus->consCoreNum;
		int core = cpus->cons[index];  
		int chipId = getChipByCoreId(core);
		int tid = consumerIds[i];
		consumerToCore->insert(pair<int,int>(tid,core));
		consumerToChip->insert(pair<int,int>(tid,chipId));
	}
	for(int i = 0; i < cpus->prodThreadsNum; i++)
	{
		int index = i % cpus->prodCoreNum;
		int core = cpus->prods[index];  
		int chipId = getChipByCoreId(core);
		int tid = producerIds[i];
		producerToCore->insert(pair<int,int>(tid,core));
		producerToChip->insert(pair<int,int>(tid,chipId));
	}
}


void Config::init(int* _producerIds, int* _consumerIds)
{
	producerIds = _producerIds;
	consumerIds = _consumerIds;
	initThreadsToChipMap();
}


void Config::readConfiguration(const char* configFile)
{
	ifstream configStream(configFile);
	if(!configStream.is_open())
	{
		cout << "could not open configuration file";
		exit(-1);
	}

	// read config file into a <property name, property value> hash map
	map<string,string> configProperties;
	while(configStream.good())
	{
		string line;
		getline(configStream,line);
		int seperator = line.find('=');
		if(seperator == (int)string::npos || line[0] == '#'){continue;}
		string propertyName = line.substr(0,seperator);
		string propertyVal = line.substr(seperator+1,line.length()-seperator-1);
		configProperties.insert(pair<string,string>(propertyName,propertyVal));
	}
	configStream.close();

	// set Config's field according to the properties read from file
	map<string,string>::iterator it;

	cpus = new CpuParams();  

	cpus->forceAssignment = false;
	it = configProperties.find("force");
	if(it != configProperties.end())
	{
		cpus->forceAssignment = (it->second).compare("yes") == 0 ? true : false;
	}
	
	cpus->crossChipWorkStealing = true;
	it = configProperties.find("crossChipWorkStealing");
	if(it != configProperties.end())
	{
		cpus->crossChipWorkStealing = (it->second).compare("yes") == 0 ? true : false;
	}

	cpus->prods = NULL;
	it = configProperties.find("prods");
	if(it != configProperties.end())
	{
		string prodStr = it->second;
		cpus->prods = parseThreadCores(prodStr,cpus->prodCoreNum);
	}

	cpus->cons = NULL;
	it = configProperties.find("cons");
	if(it != configProperties.end())
	{
		string consStr = it->second;
		cpus->cons = parseThreadCores(consStr,cpus->consCoreNum);
	}

	cpus->chips = NULL;
	it = configProperties.find("chips");
	if(it != configProperties.end())
	{
		string chipStr = it->second;
		cpus->chips = parseChipCores(chipStr, cpus->chipNum, cpus->coresPerChip);
	}

	cpus->prodThreadsNum = 0;
	it = configProperties.find("prodThreadsNum");
	if(it != configProperties.end())
	{
		cpus->prodThreadsNum = atoi((it->second).c_str());
	}

	cpus->consThreadsNum = 0;
	it = configProperties.find("consThreadsNum");
	if(it != configProperties.end())
	{
		cpus->consThreadsNum = atoi((it->second).c_str());
	}

	peakLength = 0;
	it = configProperties.find("peakLength");
	if(it != configProperties.end())
	{
		peakLength = atoi((it->second).c_str());
	}

	timeBetweenPeaks = 0;
	it = configProperties.find("timeBetweenPeaks");
	if(it != configProperties.end())
	{
		timeBetweenPeaks = atoi((it->second).c_str());
	}

	timeToRun = 0;
	it = configProperties.find("timeToRun");
	if(it != configProperties.end())
	{
		timeToRun = (unsigned long)atoi((it->second).c_str());
	}

	containerType = "";
	it = configProperties.find("containerType");
	if(it != configProperties.end())
	{
		containerType = it->second;
	}

	perChipContainersNum = 1;
	it = configProperties.find("perChipContainersNum");
	if(it != configProperties.end())
	{
		perChipContainersNum = atoi((it->second).c_str());
	}

	perChipContainerType = "";
	it = configProperties.find("perChipContainerType");
	if(it != configProperties.end())
	{
		perChipContainerType = it->second;
	}

	/************* fields currently not in use ****************************/
	/*
	contentionStatistics = false;
	it = configProperties.find("contantionStatistics");
	if(it != configProperties.end())
	{
		contentionStatistics = ((it->second).compare("yes") == 0);
	}

	exitsStatistics = false;
	it = configProperties.find("exitsStatistics");
	if(it != configProperties.end())
	{
		exitsStatistics = ((it->second).compare("yes") == 0);
	}

	consType = "regular";
	it = configProperties.find("consType");
	if(it != configProperties.end())
	{
		consType = it->second;
	}

	prodType = "regular";
	it = configProperties.find("prodType");
	if(it != configProperties.end())
	{
		prodType = it->second;
	}

	shortTaskLength = 0;
	it = configProperties.find("shortTaskLength");
	if(it != configProperties.end())
	{
		shortTaskLength = atoi((it->second).c_str());
	}

	longTaskRange = 0;
	it = configProperties.find("longTaskrange");
	if(it != configProperties.end())
	{
		longTaskRange = atoi((it->second).c_str());
	}

	consFailuresThreshold = MAX_INT;
	it = configProperties.find("consFailuresThreshold");
	if(it != configProperties.end())
	{
		consFailuresThreshold = atoi((it->second).c_str());
	}

	quasiType = "";
	it = configProperties.find("quasiType");
	if(it != configProperties.end())
	{
		quasiType = it->second;
	}

	quasiFactor = 0;
	it = configProperties.find("quasiFactor");
	if(it != configProperties.end())
	{
		quasiFactor = atoi((it->second).c_str());
	}

	qRandomTries = -1;
	it = configProperties.find("qRandomTries");
	if(it != configProperties.end())
	{
		qRandomTries = atoi((it->second).c_str());
	}
	*/
	/*************************************************************************/
}


void Config::freeMem()
{
	delete[] cpus->prods;
	delete[] cpus->cons;
	for(int i = 0; i < cpus->chipNum; i++)
	{
		delete[] cpus->chips[i];
	}
	delete[] cpus->chips;
	delete cpus;
	delete producerToChip;
	delete producerToCore;
	delete consumerToChip;
	delete consumerToCore;
}

